﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace TableTopWidgets
{
    class RotateAndTranslate
    {

        public static double rntFullRotateFactor = 0.8;
        public static double rntNoRotateFactor = 0.15;

        /// <summary>
        /// Calculates and applies RNT transformation to a transformation matrix
        /// from previous, actual contact point and object center (object coordinates)
        /// </summary>
        /// <param name="previous">previous point as vector (object coordinate system)</param>
        /// <param name="actual">actual point as vector (object coordinate system)</param>
        /// <param name="objectCenter">center of object as vector (object coordinate system)</param>
        /// <param name="transformation">actual transformation matrix (ref)</param>


        public static void calculateRNT(Vector previous, Vector actual, Vector objectCenter, ref Matrix transformation)
        {
            if (previous != actual)
            {
                Matrix m = calculateRNTMatrix(previous, actual, objectCenter);
                transformation = Matrix.Multiply(m, transformation);
            }
        }

        public static Matrix calculateRNTMatrix(Vector previous, Vector actual, Vector objectCenter)
        {
            Vector d = actual - objectCenter;
            Vector r = previous - objectCenter;

            double R = objectCenter.Length;
            double dimm = 0.0;
            if (r.Length > R * rntFullRotateFactor)
            {
                dimm = 1.0;
            }
            else if (r.Length < R * rntNoRotateFactor)
            {
                dimm = 0.0;
            }
            else
            {
                double f = r.Length / R; // proportion r to R
                // dimm factor: quadratic function between translateOnlyFactor and rotateOnlyFactor
                dimm = ((f - rntNoRotateFactor) / (rntFullRotateFactor - rntNoRotateFactor)) * ((f - rntNoRotateFactor) / (rntFullRotateFactor - rntNoRotateFactor));
            }

            double angle = 0.0;
            // If the object is picked exactly at the center, the rotation calculation will result in an invalid rotation angle
            // No rotation is needed then anyways            
            if (r.Length != 0.0)
            {
                // normalize vectors for correct calculation of the rotation angle
                d.Normalize();
                r.Normalize();
                double dmr = Vector.Multiply(d, r);
                
                if (dmr >= -1.0 && dmr <= 1.0)
                {
                    angle = -Math.Acos(dmr);
                    if ((d.X * r.Y - d.Y * r.X) < 0)
                    {
                        angle = -angle;
                    }
                    angle *= dimm;
                }
            }

            Matrix m = new Matrix();

            angle = angle / Math.PI * 180;
            m.RotateAt(angle, previous.X, previous.Y);
            m.Translate(actual.X - previous.X, actual.Y - previous.Y);

            //For some reason this solves anoto performance problems *shrug*
            //System.Threading.Thread.Sleep(1);
            return m;
        }
    }
}
